﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using frag_boardgame;
using WCFCommon;
using DataBase;

namespace WCFGameService
{
    // NOTE: If you change the class name "Room" here, you must also update the reference to "Room" in App.config.
    public class RoomService : IRoom
    {

        private Room room;
        private UserInfo userInfo;

        #region IRoom Members

        public JoinRoomResult JoinRoom(string roomName, string userName)
        {
            try
            {
                userInfo = LobbyService.lobby.users[userName];
            }
            catch (KeyNotFoundException ex)
            {
                return JoinRoomResult.UserNotFound;
            }

            try
            {
                room = LobbyService.lobby.rooms[roomName];
            }
            catch (KeyNotFoundException ex)
            {

                return JoinRoomResult.RoomNotFound;
            }

            if (room.Info.nPlayers == room.Info.config.NumberOfPlayers)
                return JoinRoomResult.RoomIsFull;
            if (room.IsPlaying == true)
                return JoinRoomResult.GameStarted;

            userInfo.roomCallback = OperationContext.Current.GetCallbackChannel<IRoomCallback>();


            room.Users[userName] = userInfo;
            room.Info.nPlayers++;
            return JoinRoomResult.Succeed;
        }


        public void LeaveRoom()
        {
            room.Users.Remove(userInfo.config.Name);
            room.Info.nPlayers--;
        }

        public void Say(string message)
        {
            string sender = userInfo.config.Name;
            foreach (UserInfo user in room.Users.Values)
            {
                user.roomCallback.ReceiveMessage(sender, message);
            }
        }

        public Dictionary<string,int> GetUsers()
        {
            Dictionary<string, int> users = new Dictionary<string, int>();
            DBAdapter db = new DBAdapter();
            for (int i = 0; i < room.Users.Count; i++)
            {
                string name = room.Users.Keys.ElementAt(i);
                int score = db.getPlayerScore(name);
                if (score == -1)
                    score = 0;
                users.Add(name, score);

            }


            return users;
        }



        #endregion

        #region IRoom Members


        public void SetPlayerConfiguration(PlayerConfiguration config)
        {

        }

        #endregion




        #region IGame Members

        public void FinishCurrentTurn()
        {
            room.Game.FinishCurrentTurn();
            UpdateGame("");
            ChangeCurrentPlayer("");



        }


        public void MovePlayer(int delta, Direction direction)
        {
            Player currentPlayer = room.Game.Data.CurrentPlayer;
            room.Game.MovePlayer(delta, direction);
            UpdateGame("");
            if (currentPlayer != room.Game.Data.CurrentPlayer)
                ChangeCurrentPlayer(currentPlayer.Name);

        }



        public void Redo()
        {
            try
            {
                room.Game.Redo();
                UpdateGame(userInfo.config.Name + " redo turn");
            }
            catch (InvalidOperationException)
            {
                userInfo.roomCallback.ReceiveMessage("Server", "Can't Redo");
                
            }
        }



        public void Shoot(int targetID)
        {
            Player currentPlayer = room.Game.Data.CurrentPlayer;
            ShootingValues shootingValues = room.Game.Shoot(targetID);
            
            //Code cloning (copied from GameConsole.UI):
            string lastMessage="";
            ShootingOptionsEnum shootingRes = shootingValues.Options;
            string shooter = shootingValues.ShooterName;
            string target = shootingValues.TargetName;
            if (shootingRes == ShootingOptionsEnum.Hit)
            {
                
                lastMessage = "Player " + shooter + " hit Player " + target;
                lastMessage += "\nPlayer " + shooter + " Rolls: " + shootingValues.ShooterDices;
                lastMessage += "\nPlayer " + target + " Rolls: " + shootingValues.TargetDices;
                lastMessage += "\nDamage is: " + shootingValues.ShooterDices / shootingValues.TargetDices;


            }
            else if (shootingRes == ShootingOptionsEnum.Miss)
            {
                lastMessage = "Player " + shooter + " missed Player " + target;
            }
            else if (shootingRes == ShootingOptionsEnum.CantShoot)
            {
                lastMessage = "Player " + shooter + " can't shoot Player " + target;
            }
            else if (shootingRes == ShootingOptionsEnum.GameOver || shootingRes == ShootingOptionsEnum.PlayerKilled)
            {
                lastMessage = "Player " + target + " was killed by " + shooter;
                if (shootingRes == ShootingOptionsEnum.GameOver)
                {
                    lastMessage += "\nGame over! " + shooter + " Wins!!";
                    GameOver(lastMessage, shooter);


                }
            }

            if (!(shootingRes == ShootingOptionsEnum.GameOver))
            {
                UpdateGame(lastMessage);
                if (currentPlayer != room.Game.Data.CurrentPlayer)
                    ChangeCurrentPlayer(currentPlayer.Name);
            }
            
           


        }


        public void Undo()
        {
            try
            {
                room.Game.Undo();
                UpdateGame(userInfo.config.Name + " undo turn");
            }
            catch (InvalidOperationException)
            {
                userInfo.roomCallback.ReceiveMessage("Server", "Can't Redo");
            }
        }





        public GameData GetGameData()
        {
            return room.Game.Data;
        }

        public StatisticsTable GetStatistics()
        {
            throw new NotImplementedException();
        }






        public void StartGame()
        {


            Configuraion conf = room.Info.config;
            foreach (UserInfo user in room.Users.Values)
            {
                user.config.Control = Player.Controller.Human;
                user.config.SetStats(3, 2, 2);
                conf.addPlayer(user.config);


            }
            for (int i = 0; i < (room.Info.config.NumberOfPlayers - room.Info.nPlayers); i++) //Fill room with AI players
            {
                PlayerConfiguration AIConfiguraion = new PlayerConfiguration();
                AIConfiguraion.StartingPosition = null;
                AIConfiguraion.SetStats(3, 2, 2);
                AIConfiguraion.Control = Player.Controller.AI;
                AIConfiguraion.Name = "AI " + (i + 1);
                conf.addPlayer(AIConfiguraion);
            }
            room.Game.New(conf);
            room.Game.StartGame();
            room.Game.IsCommunication = true;
            UpdateGame("");
  
            // write entry to games table
            if (room.IsPlaying == false)
            {
                // create game entry in games history table.
                DBAdapter dba = new DBAdapter();
                room.RoomID = dba.createGameEnty(room.Info.name, DateTime.Now);
                // add history entry to all enlisted players to 

                foreach (UserInfo userInfo in room.Users.Values)
                {
                    if ((userInfo.config.Control == Player.Controller.Human))
                    {
                        dba.createHistoryEntry(room.RoomID, userInfo.config.Name);
                    }
                }
            }

            room.IsPlaying = true;
            ChangeCurrentPlayer("");

        }

        private void UpdateGame(string message)
        {

            foreach (UserInfo user in room.Users.Values)
            {
                user.roomCallback.UpdateData(room.Game.Data,message);


            }
        }
        private int GetPlayerScore(string name)
        {
            //Need to connecnt to DB.
            //the method gets user name and return his current scroe from DB
            DBAdapter dba = new DBAdapter();
            return dba.getPlayerScore(name);
        }
        private void IncresePlayerScore(string name, int score)
        {
            //Need to connecnt to DB.   
            //The method get's user name and a score and adds the scroe to his current score.
            DBAdapter dba = new DBAdapter();
            dba.addScoreToPlayer(name, score);
        
        }

        private void GameOver(string message, string name)
        {
            //DBAdapter dba = new DBAdapter();

            int ScroeSum = 0;
            foreach (UserInfo user in room.Users.Values)
            {
                if (user.config.Control == Player.Controller.Human && !user.config.Name.ToLower().StartsWith("guest"))
                {
                    /*
                    
                    DBPlayerInfo playerInfo = user.dBplayerInfo;
                    playerInfo.GamesPlayed += 1;
                    if (playerInfo.Username == name)
                    {
                        playerInfo.GamesWon += 1;
                        playerInfo.Score += 1;

                    }
                    dba.updatePlayerInfo(playerInfo);
                    
                     */

                }
                
                string username = user.config.Name;
                if (!username.ToLower().StartsWith("guest") && !(username==name))
                    ScroeSum +=  GetPlayerScore(user.config.Name);

            
                user.roomCallback.GameOver(message);
            }

            IncresePlayerScore(name, ScroeSum / 4);
            room.IsPlaying = false;
        }
        private void ChangeCurrentPlayer(string prev)
        {
            if (prev != "")
            {
                UserInfo prevUser = room.Users[prev];
                prevUser.roomCallback.SetCurrentPlayer();
            }

            string currentName = room.Game.Data.CurrentPlayer.Name;

            if (room.Game.Data.CurrentPlayer.Control == Player.Controller.Human)
            {
                UserInfo current = room.Users[currentName];
                current.roomCallback.SetCurrentPlayer();
            }
            else
            {
                AI.PlayAI(room.Game);
                if (room.Game.Data.GetPlayersList().Count > 1)
                {
                    UpdateGame(currentName + " has made a move");
                    ChangeCurrentPlayer("");
                }
                else
                {
                    UpdateGame("Game over!\n" + room.Game.Data.CurrentPlayer.Name + " Wins!");

                }
                
                  
            }


        }



        #endregion

    }
}

